import json

from marshmallow import ValidationError
from sqlalchemy.exc import SQLAlchemyError

from common.ApiResponse import ApiResponse
from common.BaseResponse import BaseResponse
from common.ErrorCode import ErrorCode
from constant.CommonConstant import SORT_ORDER_DESC, SORT_ORDER_ASC
from my_decorator.AuthCheck import auth_check
from constant.UserConstant import ADMIN_ROLE, DEFAULT_ROLE, BAN_ROLE
from utils.ThreadLocal import ThreadLocalUtil
from utils.douBaoAI import system_prompt, douBaoAI
from .validate import *
from models import Question, db, App
from flask import request

addQuestionSchema = AddQuestionSchema()
questionAnswerSchema = QuestionAnswerSchema()
questionEditSchema = QuestionEditSchema()
questionQuerySchema = QuestionQuerySchema()
questionUpdateSchema = QuestionUpdateSchema()
aiAddQuestionSchema = AIAddQuestionSchema()


def addQuestion():
    data = request.json
    try:
        addQuestionSchema.load(data)
        question_contents = data.get('questionContent')

        json_str = ""
        if question_contents is not None:
            try:
                #
                json_str = json.dumps(question_contents, ensure_ascii=False, indent=4)
                print(json_str)
                question = Question(
                    questionContent=json_str,
                    appId=data.get('appId'),
                    userId=ThreadLocalUtil.get().get('id')
                )
                db.session.add(question)
                db.session.commit()
                return ApiResponse.success(data="添加成功")
            except Exception as e:
                print(f"转换为 JSON 字符串时出错: {e}")
                errorResponse = BaseResponse.from_error_code(error_code=ErrorCode.OPERATION_ERROR)
                return ApiResponse.error_from_baseResponse(baseResponse=errorResponse, data="题目DTO转换失败")
        else:
            print(f"questionContents is None")
            errorResponse = BaseResponse.from_error_code(error_code=ErrorCode.PARAMS_ERROR)
            return ApiResponse.error_from_baseResponse(baseResponse=errorResponse, data="questionContents is None")
    except ValidationError as err:
        print(f"添加参数校验失败: {str(err)}")
        errorResponse = BaseResponse.from_error_code(error_code=ErrorCode.PARAMS_ERROR)
        return ApiResponse.error_from_baseResponse(baseResponse=errorResponse, data="添加题目参数错误")


async def AIAddQuestion():
    data = request.json
    try:
        add_data = aiAddQuestionSchema.load(data)
        messages = add_data.get('messages', None)
        appId = add_data.get('AppId', None)
        if not isinstance(appId, int):
            appId = int(appId)
        app: App = App.query.get(appId)
        if app is None:
            print("App不存在")
            errorResponse = BaseResponse.from_error_code(error_code=ErrorCode.PARAMS_ERROR)
            return ApiResponse.error_from_baseResponse(baseResponse=errorResponse, data="App不存在")
        questionNumber = add_data.get('QuestionNumber')
        if not isinstance(questionNumber, int):
            questionNumber = int(questionNumber)
        OptionNumber = add_data.get('OptionNumber')
        if not isinstance(OptionNumber, int):
            OptionNumber = int(OptionNumber)
        system_message = system_prompt
        userPrompt = add_data.get('userPrompt', '请帮我生成题目')
        user_message = generate_user_prompt(app, questionNumber, OptionNumber, userPrompt)
        stream = True
        result = await douBaoAI.query(messages, system_message, user_message, stream)
        print(type(result))
        print(result)
        left = result.find('[')
        right = result.rfind(']')
        result = result[left:right+1]
        return ApiResponse.success(data=json.loads(result))
    except ValidationError as e:
        print(e)
        baseResponse = BaseResponse.from_error_code(ErrorCode.OPERATION_ERROR)
        return ApiResponse.error_from_baseResponse(baseResponse=baseResponse, data=e)


def deleteQuestion():
    question_id = int(request.args.get('id'))
    if question_id is None:
        print("未获取到 question_id")
        errorResponse = BaseResponse.from_error_code(error_code=ErrorCode.PARAMS_ERROR)
        return ApiResponse.error_from_baseResponse(baseResponse=errorResponse, data="参数传递错误")
    user = ThreadLocalUtil.get()
    user_id = user.get('id')
    id = question_id
    question = db.session.query(Question).filter(Question.id == id).first()
    if not question:
        print("题目不存在")
        errorResponse = BaseResponse.from_error_code(error_code=ErrorCode.PARAMS_ERROR)
        return ApiResponse.error_from_baseResponse(baseResponse=errorResponse, data="删除题目不存在")
    # 仅本人或管理员可删除
    if question.userId != user_id and user.get('user_role') != ADMIN_ROLE:
        print("权限不足")
        errorResponse = BaseResponse.from_error_code(error_code=ErrorCode.NO_AUTH_ERROR)
        return ApiResponse.error_from_baseResponse(baseResponse=errorResponse, data="权限不足")
    # 操作逻辑删除
    if question.isDelete == 0:
        question.isDelete = 1
        db.session.commit()
        return ApiResponse.success(data="删除成功")
    else:
        question.isDelete = 0
        db.session.commit()
        return ApiResponse.success(data="恢复成功")


def validQuestion(question: Question, add: bool):
    if not question:
        print("题目不存在")
        errorResponse = BaseResponse.from_error_code(error_code=ErrorCode.PARAMS_ERROR)
        return ApiResponse.error_from_baseResponse(baseResponse=errorResponse, data="题目不存在")
    question_contents = question.questionContent
    app_id = question.appId
    if (add):
        if not question_contents:
            print("题目内容不存在")
            errorResponse = BaseResponse.from_error_code(error_code=ErrorCode.PARAMS_ERROR)
            return ApiResponse.error_from_baseResponse(baseResponse=errorResponse, data="题目内容不存在")
        if not app_id:
            print("AppId不存在")
            errorResponse = BaseResponse.from_error_code(error_code=ErrorCode.PARAMS_ERROR)
            return ApiResponse.error_from_baseResponse(baseResponse=errorResponse, data="AppId不存在")
    if app_id:
        app = App.query.filter(App.id == app_id).first()
        if not app:
            print("App不存在")
            errorResponse = BaseResponse.from_error_code(error_code=ErrorCode.PARAMS_ERROR)
            return ApiResponse.error_from_baseResponse(baseResponse=errorResponse, data="App不存在")


@auth_check(required_roles=[ADMIN_ROLE])
def updateQuestion():
    data = request.json
    try:
        error = questionUpdateSchema.load(data)
        id = data.get('id')
        question_contents = data.get('questionContent')
        if question_contents is not None:
            try:
                json_str = json.dumps(question_contents, ensure_ascii=False, indent=4)
                print(json_str)
                question = Question(
                    questionContent=json_str
                )
                validQuestion(question, False)
                # 判断是否存在
                old_question = Question.query.filter(Question.id == id).first()
                if not old_question:
                    print("题目不存在")
                    errorResponse = BaseResponse.from_error_code(error_code=ErrorCode.PARAMS_ERROR)
                    return ApiResponse.error_from_baseResponse(baseResponse=errorResponse, data="题目不存在")
                try:
                    old_question.questionContent = json_str
                    db.session.commit()
                    return ApiResponse.success(data="更新成功！")
                except SQLAlchemyError as e:
                    print("更新操作失败")
                    errorResponse = BaseResponse.from_error_code(error_code=ErrorCode.OPERATION_ERROR)
                    return ApiResponse.error_from_baseResponse(baseResponse=errorResponse, data="更新操作失败存在")
            except Exception as e:
                print(f"转换为 JSON 字符串时出错: {e}")
                errorResponse = BaseResponse.from_error_code(error_code=ErrorCode.OPERATION_ERROR)
                return ApiResponse.error_from_baseResponse(baseResponse=errorResponse, data="题目DTO转换失败")
        else:
            print(f"questionContents is None")
            errorResponse = BaseResponse.from_error_code(error_code=ErrorCode.PARAMS_ERROR)
            return ApiResponse.error_from_baseResponse(baseResponse=errorResponse, data="questionContents is None")

    except ValidationError as err:
        print(f"更新参数校验失败: {str(err)}")
        errorResponse = BaseResponse.from_error_code(error_code=ErrorCode.PARAMS_ERROR)
        return ApiResponse.error_from_baseResponse(baseResponse=errorResponse, data="更新题目参数错误")


def getQuestionVOById():
    try:
        id = request.args.get("id")
        if not isinstance(id, int):
            id = int(id)
        question = Question.query.filter(Question.appId == id).first()
        if not question:
            print(f"题目不存在")
            errorResponse = BaseResponse.from_error_code(error_code=ErrorCode.PARAMS_ERROR)
            return ApiResponse.error_from_baseResponse(baseResponse=errorResponse, data="题目不存在")
        return ApiResponse.success(data=question.question_user_to_json_VO())
    except Exception as e:
        print(f"获取题目参数有误: " + f"{str(e)}")
        errorResponse = BaseResponse.from_error_code(error_code=ErrorCode.PARAMS_ERROR)
        return ApiResponse.error_from_baseResponse(baseResponse=errorResponse, data="获取题目参数有误")


def query_database_for_all(query_data, user_map, isMy: bool = False):
    pageSize = query_data.get('pageSize')
    current = query_data.get('current')

    if user_map.get('user_role') == DEFAULT_ROLE:
        if pageSize > 20:
            print("用户访问异常")
            errorResponse = BaseResponse.from_error_code(ErrorCode.PARAMS_ERROR)
            return ApiResponse.error_from_baseResponse(errorResponse, data="用户访问异常")
    query = Question.query
    # 查询条件
    query_filed = {
        'id': lambda q, v: q.filter(Question.id == v),
        'questionContent': lambda q, v: q.filter(Question.questionContent.contains(v)),
        'appId': lambda q, v: q.filter(Question.appId == v),
        'notId': lambda q, v: q.filter(Question.id != v),
        'userId': lambda q, v: q.filter(Question.userId == v),
        'isDelete': lambda q, v: q.filter(Question.isDelete == v),
    }
    # 构建查询
    for filed, condition_func in query_filed.items():
        value = query_data.get(filed)
        if value is not None:
            query = condition_func(query, value)
    # 给用户看到得是没有逻辑删除的
    if user_map.get('user_role') == DEFAULT_ROLE:
        query = query.filter(Question.isDelete == 0)
    # 如果是给自己看的
    if isMy:
        query = query.filter(Question.userId == user_map.get('id'))
        # 排序字段
    sort_fields = {
        'id': Question.id,
        'questionContent': Question.questionContent,
        'appId': Question.appId,
        'userId': Question.userId,
        'createTime': Question.createTime,
        'updateTime': Question.updateTime,
    }
    filed_name = query_data.get('sortField')
    if filed_name is not None:
        sortField = sort_fields.get(filed_name)
        sortOrder = query_data.get('sortOrder')
        if sortOrder == SORT_ORDER_DESC:
            sortField = sortField.desc()
        elif sortOrder == SORT_ORDER_ASC:
            sortField = sortField.asc()
        else:
            print("排序字段有误，参数校验失败")
            errorResponse = BaseResponse.from_error_code(ErrorCode.PARAMS_ERROR)
            return ApiResponse.error_from_baseResponse(errorResponse, data="排序字段有误，参数校验失败")
        query = query.order_by(sortField)
    return query.paginate(page=current, per_page=pageSize)


# 给管理员看的
@auth_check(required_roles=[ADMIN_ROLE])
def listQuestionsByPage():
    data = request.json
    for key in ["pageSize", "current", "sortField", "sortOrder", "isDelete"]:
        if data.get(key) is None:
            data[key] = questionQuerySchema.fields[key].default
    try:
        query_data = questionQuerySchema.load(data)
        user_map = ThreadLocalUtil.get()
        pagination = query_database_for_all(query_data, user_map)
        base_data = {
            "total": pagination.total,
            "current": pagination.page,
            "pageSize": pagination.per_page,
            "pages": pagination.pages,
            # 这里要区分一下哪个是给用户看的，哪个是给管理员看的,用户不需要看到逻辑删除字段
            # 管理员不需要看到用户具体信息，
            "questionContent": [(question.question_admin_to_json_VO() if user_map.get(
                "user_role") == ADMIN_ROLE else question.question_user_to_json_VO()) for question in pagination.items],
        }
        return ApiResponse.success(data=base_data)
    except ValidationError as err:
        print(f"查询参数校验失败: {str(err)}")
        errorResponse = BaseResponse.from_error_code(error_code=ErrorCode.PARAMS_ERROR)
        return ApiResponse.error_from_baseResponse(baseResponse=errorResponse, data="查询题目参数失败")


# 给用户看的
def listQuestionVOByPage():
    data = request.json
    try:
        query_data = questionQuerySchema.load(data)
        user_map = ThreadLocalUtil.get()
        pagination = query_database_for_all(query_data, user_map)
        base_data = {
            "total": pagination.total,
            "current": pagination.page,
            "pageSize": pagination.per_page,
            # 这里要区分一下哪个是给用户看的，哪个是给管理员看的,用户不需要看到逻辑删除字段
            # 管理员不需要看到用户具体信息，
            "questionContent": [(question.question_admin_to_json_VO() if user_map.get(
                "user_role") == ADMIN_ROLE else question.question_user_to_json_VO()) for question in pagination.items],
        }
        return ApiResponse.success(data=base_data)
    except ValidationError as err:
        print(f"查询参数校验失败: {str(err)}")
        errorResponse = BaseResponse.from_error_code(error_code=ErrorCode.PARAMS_ERROR)
        return ApiResponse.error_from_baseResponse(baseResponse=errorResponse, data="查询题目参数失败")


def listMyQuestionsByPage():
    data = request.json
    try:
        query_data = questionQuerySchema.load(data)
        user_map = ThreadLocalUtil.get()
        pagination = query_database_for_all(query_data, user_map, True)
        base_data = {
            "total": pagination.total,
            "current": pagination.page,
            "pageSize": pagination.per_page,
            # 这里要区分一下哪个是给用户看的，哪个是给管理员看的,用户不需要看到逻辑删除字段
            # 管理员不需要看到用户具体信息，
            "questionContent": [(question.question_admin_to_json_VO() if user_map.get(
                "user_role") == ADMIN_ROLE else question.question_user_to_json_VO()) for question in pagination.items],
        }
        return ApiResponse.success(data=base_data)
    except ValidationError as err:
        print(f"查询参数校验失败: {str(err)}")
        errorResponse = BaseResponse.from_error_code(error_code=ErrorCode.PARAMS_ERROR)
        return ApiResponse.error_from_baseResponse(baseResponse=errorResponse, data="查询题目参数失败")


def editQuestion():
    data = request.json
    try:
        edit_data = questionEditSchema.load(data)
        question = Question(
            id=edit_data.get('id'),
        )
        questionContentDTO = edit_data.get('questionContent')
        newQuestionContent = json.dumps(questionContentDTO, ensure_ascii=False, indent=4)
        question.questionContent = newQuestionContent
        validQuestion(question, False)
        user_map = ThreadLocalUtil.get()
        question_id = edit_data.get('id')
        old_question = db.session.query(Question).filter_by(id=question_id).first()
        if not old_question:
            print(f"id为{question_id}旧的Question不存在")
            errorResponse = BaseResponse.from_error_code(error_code=ErrorCode.NOT_FOUND_ERROR)
            return ApiResponse.error_from_baseResponse(baseResponse=errorResponse,
                                                       data=f"id为{question_id}旧的Question不存在")
        if user_map.get("user_role") != ADMIN_ROLE and old_question.userId != user_map.get("userId"):
            print("仅本人或管理员可编辑")
            errorResponse = BaseResponse.from_error_code(error_code=ErrorCode.NOT_FOUND_ERROR)
            return ApiResponse.error_from_baseResponse(baseResponse=errorResponse,
                                                       data="仅本人或管理员可编辑")
        try:
            # 修改为直接赋值
            old_question.questionContent = newQuestionContent
            db.session.commit()
            return ApiResponse.success()
        except SQLAlchemyError as e:
            print("更新操作失败")
            errorResponse = BaseResponse.from_error_code(error_code=ErrorCode.OPERATION_ERROR)
            return ApiResponse.error_from_baseResponse(baseResponse=errorResponse, data="更新操作失败存在")
    except ValidationError as err:
        print(f"编辑参数校验失败: {str(err)}")
        errorResponse = BaseResponse.from_error_code(error_code=ErrorCode.PARAMS_ERROR)
        return ApiResponse.error_from_baseResponse(baseResponse=errorResponse, data="编辑参数校验失败")


def generate_user_prompt(app: App, questionNum: int, optionNum: int, user_prompt: str = '请帮我生成题目'):
    appName = app.appName
    appDesc = app.appDesc
    appType = "测评类" if app.appType == 1 else "得分类"
    userPrompt = f'''
        请帮我生成一个应用名称是：{appName},
                    应用描述是: {appDesc}，
                    应用类型是: {appType},
                    题目数量是: {questionNum},
                    每个题目的选项数量是: {optionNum},
                    的题目集合
        用户提示：{user_prompt}
    '''
    return userPrompt
